package edu.nyu.hps.assignment3;

public class NoTipping {
	int[] weights, rWtPos, bWtPos, supports = { -3, -1 };
	int[] gamePositions = { 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
			0, 0, 0, 0 };
	int[][] unWantedState = { { -4, -10 }, { -3, -7 }, { -2, -6 }, { -2, -5 },
			{ -2, -4 }, { -2, -4 }, { -2, -4 }, { -2, -4 },
			{ -2, -3 }, { -2, -3 } };
	boolean[] insetone = new boolean[21];
	int player, maxWeight, mytorque1, mytorque2, besttorque1 = 1000,
			bestWt = 100, bestPos = 100;
	int notOnBoard = -50;
	boolean addPhase = true;
	boolean firstMoveasRed = true;

	public NoTipping(int p, int wt, boolean ph) {
		mytorque1 = -6;
		mytorque2 = 6;
		player = p;
		maxWeight = wt;
		addPhase = ph;
		weights = new int[wt];
		rWtPos = new int[wt];
		bWtPos = new int[wt];
		for (int i = 0; i < wt; i++) {
			weights[i] = i + 1;
			rWtPos[i] = -50;
			bWtPos[i] = -50;

		}
		for (int i = 0; i < 21; i++) {
			insetone[i] = false;
		}
	}

	/**
	 * Finds those states of the board where a alone weight on the board will
	 * keep it stable This states need to be avoided as the red player and
	 * enforced as the blue player.
	 * 
	 * @param p
	 * @param w
	 * @return true or false
	 */
	public boolean isInUnwantedSet(int p, int w) {
		return p <= unWantedState[w - 1][0] && p >= unWantedState[w - 1][1];
	}

	public void updateSetOne() {
		for (int i = -2; i <= -10; i--) {
			if (isInUnwantedSet(i, gamePositions[i + 10]))
				insetone[i + 10] = true;
		}
	}

	public String firstMoveOfRed() {
		besttorque1 = 1000;
		bestWt = 100;
		bestPos = 100;
		for (int i = maxWeight - 1; i >= 0; i--) {
//			for(int k = 0; k<rWtPos.length;k++) System.out.print(rWtPos[k]+" ");
//			System.out.println();
			if (rWtPos[i] == notOnBoard) {
				for (int j = -10; j <= -2; j++) {
					int t0 = (j - supports[0]) * -(i + 1);
					int t1 = (j - supports[1]) * -(i + 1);
					if (gamePositions[j + 10] == 0 && mytorque1 + t0 <= 0
							&& mytorque2 + t1 >= 0) {
						if (besttorque1 > mytorque1 + t0) {
							besttorque1 = mytorque1 + t0;
							mytorque1 += t0;
							mytorque2 += t1;
							bestWt = i + 1;
							bestPos = j;
						}
					}
				}
			}
		}
		if (besttorque1 != 1000) {
			
//			System.out.println("BestWt from 1: " + bestWt);
			gamePositions[bestPos + 10] = bestWt;
//			for(int k = 0; k<rWtPos.length;k++) System.out.print(rWtPos[k]+" ");
//			System.out.println();
			rWtPos[bestWt-1] = bestPos;
			return (bestWt + ":" + bestPos);
		}
		return ("Not Possible");
	}

	public String addingAsRed() {
		// Blocking set one positions
		for (int i = maxWeight - 1; i >= 0; i--) {
			if (rWtPos[i] == notOnBoard) {
				for (int j = -10; j <= -2; j++) {
					int t0 = (j - supports[0]) * -(i + 1);
					int t1 = (j - supports[1]) * -(i + 1);
					if (gamePositions[j + 10] == 0 && mytorque1 + t0 <= 0
							&& mytorque2 + t1 >= 0
							&& (!isInUnwantedSet(j, i + 1))) {
						mytorque1 += t0;
						mytorque2 += t1;
						gamePositions[j + 10] = i + 1;
						rWtPos[i] = j;
						System.out.println("BestWt from 2: " + i+1);
						return ((i + 1) + ":" + j);
					}
				}
			}
		}

		// Adding at positions besides set1
		for (int i = maxWeight - 1; i >= 0; i--) {
			if (rWtPos[i] == notOnBoard) {
				for (int j = -10; j <= 10; j++) {
					int t0 = (j - supports[0]) * -(i + 1);
					int t1 = (j - supports[1]) * -(i + 1);
					if (gamePositions[j + 10] == 0 && mytorque1 + t0 <= 0
							&& mytorque2 + t1 >= 0
							&& (!isInUnwantedSet(j, i + 1))) {
						mytorque1 += t0;
						mytorque2 += t1;
						gamePositions[j + 10] = i + 1;
						rWtPos[i] = j;
						return ((i + 1) + ":" + j);
					}
				}
			}
		}

		// Adding at the remaining
		for (int i = maxWeight - 1; i >= 0; i--) {
			if (rWtPos[i] == notOnBoard) {
				for (int j = -10; j <= 10; j++) {
					int t0 = (j - supports[0]) * -(i + 1);
					int t1 = (j - supports[1]) * -(i + 1);
					if (gamePositions[j + 10] == 0 && mytorque1 + t0 <= 0
							&& mytorque2 + t1 >= 0) {
						mytorque1 += t0;
						mytorque2 += t1;
						gamePositions[j + 10] = i + 1;
						rWtPos[i] = j;
						return ((i + 1) + ":" + j);
					}
				}
			}
		}

		// Adding to tip
		for (int i = maxWeight - 1; i >= 0; i--) {
			if (rWtPos[i] == notOnBoard) {
				for (int j = -10; j <= 10; j++) {
					if (gamePositions[j + 10] == 0) {
						return ((i + 1) + ":" + j);
					}
				}
			}
		}
		return "error adding as red";
	}

	public String addingAsBlue() {

		// Adding at set1 positions
		for (int i = maxWeight - 1; i >= 0; i--) {
			if (bWtPos[i] == notOnBoard) {
				for (int j = unWantedState[i][1]; j <= unWantedState[i][0]; j++) {
					int t0 = (j - supports[0]) * -(i + 1);
					int t1 = (j - supports[1]) * -(i + 1);
					if (gamePositions[j + 10] == 0 && mytorque1 + t0 <= 0
							&& mytorque2 + t1 >= 0) {
						mytorque1 += t0;
						mytorque2 += t1;
						gamePositions[j + 10] = i + 1;
						bWtPos[i] = j;
						return ((i + 1) + ":" + j);
					}
				}
			}
		}

		// Adding at remaining positons
		for (int i = maxWeight - 1; i >= 0; i--) {
			if (bWtPos[i] == notOnBoard) {
				for (int j = 10; j >= -10; j--) {
					int t0 = (j - supports[0]) * -(i + 1);
					int t1 = (j - supports[1]) * -(i + 1);
					if (gamePositions[j + 10] == 0 && mytorque1 + t0 <= 0
							&& mytorque2 + t1 >= 0) {
						mytorque1 += t0;
						mytorque2 += t1;
						gamePositions[j + 10] = i + 1;
						bWtPos[i] = j;
						return ((i + 1) + ":" + j);
					}
				}
			}
		}

		// Adding to tip
		for (int i = maxWeight - 1; i >= 0; i--) {
			if (bWtPos[i] == notOnBoard) {
				for (int j = 10; j >= -10; j--) {
					if (gamePositions[j + 10] == 0) {
						return ((i + 1) + ":" + j);
					}
				}
			}
		}
		return "error adding as blue";
	}

	public String removeAsRed() {

		// Removing set1 positions
		for (int i = -2; i >= -10; i--) {
//			System.out.println("The game position at" + i + "is : "
//					+ gamePositions[i + 10]);
			if (gamePositions[i + 10] != 0) {
				int t0 = (i - supports[0]) * -gamePositions[i + 10];
				int t1 = (i - supports[1]) * -gamePositions[i + 10];
				if (insetone[i + 10] && mytorque1 - t0 <= 0
						&& mytorque2 - t1 >= 0) {
					mytorque1 -= t0;
					mytorque2 -= t1;
					// gamePositions[i+10] = 0;
					return (i + "");
				}
			}
		}

		// Removing other positions
		for (int i = 10; i >= -10; i--) {
//			System.out.println("The game position at" + i + "is : "
//					+ gamePositions[i + 10]);
			if (gamePositions[i + 10] != 0) {
				int t0 = (i - supports[0]) * -gamePositions[i + 10];
				int t1 = (i - supports[1]) * -gamePositions[i + 10];
				// System.out.println("The torque t0 in loop2 is: " + t0);
				// System.out.println("The torque t1 in loop2 is: " + t1);
				// System.out.println("i: " + i);
				if ((!insetone[i + 10]) && mytorque1 - t0 <= 0
						&& mytorque2 - t1 >= 0) {
					mytorque1 -= t0;
					mytorque2 -= t1;
					// gamePositions[i+10] = 0;
					return (i + "");
				}
			}
		}

		// Removing to anything and everything
		for (int i = 10; i >= -10; i--) {
			if (gamePositions[i + 10] != 0) {
				int t0 = (i - supports[0]) * -gamePositions[i + 10];
				int t1 = (i - supports[1]) * -gamePositions[i + 10];
				// System.out.println("The torque t0 in loop2 is: " + t0);
				// System.out.println("The torque t1 in loop2 is: " + t1);
				System.out.println("i: " + i);
				if (mytorque1 - t0 <= 0 && mytorque2 - t1 >= 0) {
					mytorque1 -= t0;
					mytorque2 -= t1;
					// gamePositions[i+10] = 0;
					return (i + "");
				}
			}
		}

		// Removing to tip
		for (int i = 10; i >= -10; i--) {
			if (gamePositions[i + 10] != 0) {
				return (i + "");
			}

		}
		return "error removing as red";
	}

	public String removeAsBlue() {

		// Removing not in set1 positions
		for (int i = -10; i <= 10; i++) {
			if (gamePositions[i + 10] != 0) {
				int t0 = (i - supports[0]) * -gamePositions[i + 10];
				int t1 = (i - supports[1]) * -gamePositions[i + 10];
				if ((!insetone[i + 10]) && mytorque1 - t0 <= 0
						&& mytorque2 - t1 >= 0) {
					mytorque1 -= t0;
					mytorque2 -= t1;
					// gamePositions[i+10] = 0;
					return (i + "");
				}
			}
		}

		// Removing from set1 positions
		for (int i = 10; i >= -10; i--) {
			if (gamePositions[i + 10] != 0) {
				int t0 = (i - supports[0]) * -gamePositions[i + 10];
				int t1 = (i - supports[1]) * -gamePositions[i + 10];
				if (insetone[i + 10] && mytorque1 - t0 <= 0
						&& mytorque2 - t1 >= 0) {
					mytorque1 -= t0;
					mytorque2 -= t1;
					// gamePositions[i+10] = 0;
					return (i + "");
				}
			}
		}

		// Removing anything and everything
		for (int i = 10; i >= -10; i--) {
			if (gamePositions[i + 10] != 0) {
				int t0 = (i - supports[0]) * -gamePositions[i + 10];
				int t1 = (i - supports[1]) * -gamePositions[i + 10];
				if (mytorque1 - t0 <= 0 && mytorque2 - t1 >= 0) {
					mytorque1 -= t0;
					mytorque2 -= t1;
					// gamePositions[i+10] = 0;
					return (i + "");
				}
			}
		}

		// Removing to tip
		for (int i = 10; i >= -10; i--) {
			if (gamePositions[i + 10] != 0) {
				return (i + "");
			}

		}
		return "error removing as blue";
	}

	public String process() {
		if (addPhase) // adding phase
		{
			if (player == 0) // red player
			{
				String temp = firstMoveOfRed();
				return temp.equalsIgnoreCase("Not Possible")? addingAsRed():temp;
//				return addingAsRed();
			} else {
				return addingAsBlue();
			}
		} else {
			if (player == 0) // red player
			{
				return removeAsRed();
			} else {
				return removeAsBlue();
			}
		}

	}

	public int[] getGamePositions() {
		return gamePositions;
	}

	public void setGamePositions(int[] gamePositions) {
		this.gamePositions = gamePositions.clone();
	}

	public int getPlayer() {
		return player;
	}

	public void setPlayer(int player) {
		this.player = player;
	}

	public int getMytorque1() {
		return mytorque1;
	}

	public void setMytorque1(int mytorque1) {
		this.mytorque1 = mytorque1;
	}

	public int getMytorque2() {
		return mytorque2;
	}

	public void setMytorque2(int mytorque2) {
		this.mytorque2 = mytorque2;
	}

	public boolean isAddPhase() {
		return addPhase;
	}

	public void setMaxWeight(int maxWeight) {
		this.maxWeight = maxWeight;
	}
}
